using System;
using System.Reflection;
using System.Collections.Generic;
using System.Text;

using Crainiate.Data.Persistence.Cache;

namespace Crainiate.Data.Persistence.Providers.Labelling
{
    //Determines equality of an object on hash code not on instance
    public abstract class CompoundHash
    {
        public override bool Equals(object obj)
        {
            return (GetHashCode() == obj.GetHashCode());
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
        
    public class TypeCompoundHash: CompoundHash
    {
        private Type _type;
        private int _cache;

        public TypeCompoundHash()
        {
            
        }

        public TypeCompoundHash(Type type)
        {
            Type = type;
        }

        public virtual Type Type
        {
            get 
            { 
                return _type; 
            }
            set 
            {
                _cache = 0;
                _type = value; 
            }
        }

        public override int GetHashCode()
        {
            //Return from cache if available
            if (_cache != 0) return _cache;

            _cache = Math.Abs(ToString().GetHashCode());
            return _cache;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(Type.FullName);
            return builder.ToString();
        }
    }

    public class TypePropertyCompoundHash: TypeCompoundHash
    {
        private PropertyInfo _property;
        private int _cache;

        public TypePropertyCompoundHash()
        {

        }

        public TypePropertyCompoundHash(Type type, PropertyInfo property): base(type)
        {
            Property = property;
        }

        public virtual PropertyInfo Property
        {
            get
            {
                return _property;
            }
            set
            {
                _cache = 0;
                _property = value;
            }
        }

        public override int GetHashCode()
        {
            //Return from cache if available
            if (_cache != 0) return _cache;

            _cache = Math.Abs(ToString().GetHashCode());
            return _cache;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(Type.FullName);
            builder.Append(".");
            builder.Append(Property.Name);

            return builder.ToString();
        }
    }

    public class TypePropertyTypeCompoundHash : CompoundHash
    {
        private TypePropertyCompoundHash _hash;
        private Type _type;
        private int _cache;

        public TypePropertyTypeCompoundHash()
        {

        }

        public TypePropertyTypeCompoundHash(TypePropertyCompoundHash hash, Type type)
        {
            Type = type;
            Hash = hash;
        }

        public virtual TypePropertyCompoundHash Hash
        {
            get 
            { 
                return _hash; 
            }
            set 
            {
                _cache = 0;
                _hash = value; 
            }
        }

        public virtual Type Type
        {
            get
            {
                return _type;
            }
            set
            {
                _cache = 0;
                _type = value;
            }
        }

        public override int GetHashCode()
        {
            //Return from cache if available
            if (_cache != 0) return _cache;

            _cache = Math.Abs(ToString().GetHashCode());
            return _cache;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(Hash.Type.FullName);
            builder.Append(".");
            builder.Append(Hash.Property.Name);
            builder.Append(".");
            builder.Append(Type.FullName);

            return builder.ToString();
        }
    }

    public class QueryCompoundHash: CompoundHash
    {
        private IQuery _query;
        private int _cache;

        public QueryCompoundHash()
        {

        }

        public QueryCompoundHash(IQuery query)
        {
            Query = query;
        }

        public virtual IQuery Query
        {
            get
            {
                return _query;
            }
            set
            {
                _cache = 0;
                _query = value;
            }
        }

        public override int GetHashCode()
        {
            //Return from cache if available
            if (_cache != 0) return _cache;

            _cache = Math.Abs(ToString().GetHashCode());
            return _cache;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("Query<");
            builder.Append(Query.Type.FullName);
            builder.Append(">");

            return builder.ToString();
        }
    }

    public class QueryPropertyCompoundHash : QueryCompoundHash
    {
        private PropertyInfo _property;
        private int _cache;

        public QueryPropertyCompoundHash()
        {

        }

        public QueryPropertyCompoundHash(IQuery query, PropertyInfo property): base(query)
        {
            Property = property;
        }

        public virtual PropertyInfo Property
        {
            get
            {
                return _property;
            }
            set
            {
                _cache = 0;
                _property = value;
            }
        }

        public override int GetHashCode()
        {
            //Return from cache if available
            if (_cache != 0) return _cache;

            _cache = Math.Abs(ToString().GetHashCode());
            return _cache;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("Query<");
            builder.Append(Query.Type.FullName);
            builder.Append(">.");
            builder.Append(Property.Name);

            return builder.ToString();
        }
    }

    public class QueryPropertyTypeCompoundHash: CompoundHash
    {
        private QueryPropertyCompoundHash _hash;

        private Type _type;
        private int _cache;

        public QueryPropertyTypeCompoundHash()
        {

        }

        public QueryPropertyTypeCompoundHash(QueryPropertyCompoundHash hash, Type type)
        {   
            Hash = hash;
            Type = type;
        }

        public virtual Type Type
        {
            get
            {
                return _type;
            }
            set
            {
                _cache = 0;
                _type = value;
            }
        }

        public virtual QueryPropertyCompoundHash Hash
        {
            get
            {
                return _hash;
            }
            set
            {
                _cache = 0;
                _hash = value;
            }
        }

        public override int GetHashCode()
        {
            //Return from cache if available
            if (_cache != 0) return _cache;

            _cache = Math.Abs(ToString().GetHashCode());
            return _cache;
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("Query<");
            builder.Append(Hash.Query.Type.FullName);
            builder.Append(">.");
            builder.Append(Hash.Property.Name);
            builder.Append(".");
            builder.Append(Type.FullName);

            return builder.ToString();
        }
    }
}
